﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace BindTryParseMVC.Controllers
{
    public class HomeController : Controller
    {
        public async Task<IActionResult> Index(InstructorObjectId instructor)
        {
            // Manual model binding
            // 这种只能用在 MVC Razor 中，不能用在 Web API 中
            var isvalided = await TryUpdateModelAsync(instructor, "Instructor", x => x.Name, x => x.Id);
            if (isvalided)
            {
                // Do something with the instructor object
            }
            else
            {
                // Handle the error
            }
            if (await TryUpdateModelAsync<InstructorObjectId>(instructor))
            {
                // Do something with the instructor object
            }
            else
            {
                // Handle the error
            }

            return View();
        }

        /// <summary>
        ///  This is the About page.
        ///  
        /// 配置使用 XML 序列化器格式化程序
        /// </summary>
        /// <returns></returns>
        [Consumes("application/xml")]
        public IActionResult About()
        {
            return View();
        }

        /// <summary>
        /// MVC 内置的 ByteArrayModelBinder 它会把一个base-64 encoded string 使用 ByteArrayModelBinder 转换为byte[]
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null) 
                throw new ArgumentNullException("context");
            if(context.Metadata.ModelType == typeof(byte[]))
            {
                var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
                return new ByteArrayModelBinder(loggerFactory);
            }
            return null;
        }

        /// <summary>
        /// The following example shows how to use ByteArrayModelBinder to convert a base64-encoded string to a byte[] 
        /// and save the result to a file:
        /// </summary>
        /// <param name="file"></param>
        /// <param name="fileName"></param>
        public void Post([FromForm] byte[] file,string fileName)
        {
            var trustedFileName = Path.GetRandomFileName();
            var filePath = Path.Combine(trustedFileName, fileName);
            if (System.IO.File.Exists(filePath))
            {
                return;
            }
            System.IO.File.WriteAllBytes(filePath, file);
        }
        /// <summary>
        /// 下面的例子展示了如何使用 ByteArrayModelBinder 绑定model
        /// </summary>
        /// <param name="model"></param>
        public void SaveProfile([FromForm] ProfileViewModel model)
        {
            var trustedFileName = Path.GetRandomFileName();
            var filePath = Path.Combine(trustedFileName, model.Name);
            if (System.IO.File.Exists(filePath))
            {
                return;
            }
            System.IO.File.WriteAllBytes(filePath, model.File);
        }
    }


    public class ProfileViewModel
    {
        public byte[] File { get; set; }
        public string Name { get; set; }
    }

    public class InstructorObjectId
    {
        [Required]
        public ObjectId Id { get; set; }
        public string Name { get; set; }
    }
    [JsonConverter(typeof(ObjectIdConverter))]
    public record ObjectId(int id);

    /// <summary>
    /// Custom JSON converter for ObjectId
    /// </summary>
    internal class ObjectIdConverter : JsonConverter<ObjectId>
    {
        public override ObjectId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
           //  return new ObjectId(reader.GetInt32());
           return new ObjectId(JsonSerializer.Deserialize<int>(ref reader, options));
        }
        public override void Write(Utf8JsonWriter writer, ObjectId value, JsonSerializerOptions options)
        {
            writer.WriteNumberValue(value.id);
        }
    }
}
